/*
 * Copyright 2008 Carnegie Mellon University
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, 
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package edu.cmu.lti.sepia.data.resource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.servlet.ServletContext;

import org.apache.log4j.Logger;

import edu.cmu.lti.sepia.util.ExceptionUtil;
import edu.cmu.lti.sepia.util.IOUtil;

/**
 * Responsible for project specific data, not task!
 * 
 * @author Hideki
 * 
 */
public class ResourceManager {

  public static boolean debugMode = false;

  private static final Logger logger = Logger.getLogger(ResourceManager.class);

  private static final String SEPIA_HOME = "SEPIA_HOME";

  private static final String SEPIA_PROPERTIES = "sepia.properties";

  public static File sepiaHome;

  public static File uploadRepository;

  public static File sepiaProperties;

  // public static String realRoot; //not used

  public static String projectName;

  public static String indriHome;

  public static String dbHost;

  public static String dbPort;

  public static String dbUser;

  public static String dbPass;

  public static Properties p = new java.util.Properties();

  private static void storePropertyValues(Properties p) {
    dbHost = p.getProperty("db.hostname");
    dbPort = p.getProperty("db.portnumber", "3306"); // default port number is 3306 for mysql
    dbUser = p.getProperty("db.username");
    dbPass = p.getProperty("db.password");
    projectName = p.getProperty("projectName");
    indriHome = p.getProperty("indriHome");
    debugMode = Boolean.parseBoolean(p.getProperty("debugMode", "false"));
    // db_prefix
  }

  /**
   * Load the properties file. Called at the very beginning to initialize db settings etc. e.g. new
   * SQL();
   * 
   * @param application
   * @return error messages
   */
  public static String init() {
    p = getPropertiesFromHome(SEPIA_PROPERTIES);

    // application is null when called by SQL class.
    // if (application!=null) {
    // realRoot = application.getRealPath("");
    // }

    if (p != null) {
      storePropertyValues(p);
    } else {
      p = new Properties();
    }

    boolean sepiaHomeMkdirs = true;
    if (sepiaHome != null && !sepiaHome.exists()) {
      sepiaHomeMkdirs = sepiaHome.mkdirs();

      uploadRepository = new File(sepiaHome, "files");
      if (!uploadRepository.exists()) {
        uploadRepository.mkdir();
      }
    }

    StringBuilder sb = new StringBuilder();
    if (sepiaHome == null) {
      sb.append("<li>Environment variable \"SEPIA_HOME\" is not set, or Tomcat is not restarted.</li>\n");
      sb.append("<ul><li>On windows, go to Control Panel -&gt; System -&gt; Advanced &gt; Environment Variables. After setting the variable, restart the web server application</li>\n");
      sb.append("<li>If you are running tomcat from a script, edit $CATALINA_HOME/bin/startup.sh and add a line such as following:</li>\n");
      sb.append("<ul><li>Windows: <code>SET SEPIA_HOME=\"C:\\home\\sepia\\\"</code></li>\n");
      sb.append("<li>Linux: <code>export $SEPIA_HOME=\"/home/sepia/\"</code></li>\n");
    } else if (!sepiaHome.isDirectory()) {
      sb.append("<li>SEPIA_HOME is not a directory. Make sure following path is a directory: "
              + sepiaHome.getAbsolutePath() + "</li>\n");
    } else if (!sepiaHome.canRead() || !sepiaHome.canWrite()) {
      sb.append("<li>Permission is not enough. Please make sure following directory is readable and writable: "
              + sepiaHome.getAbsolutePath() + "</li>\n");
    } else if (!sepiaHomeMkdirs) {
      sb.append("<li>Tried to create the $SEPIA_HOME, but failed to do so. Check the permission or diskspace at: "
              + sepiaHome.getAbsolutePath() + "</li>\n");
    }

    // Never
    // if (p.size()==0) {
    // sb.append("<li>Cannot read the property file: "+new
    // File(System.getenv(SEPIA_HOME)).getAbsoluteFile()+"</li>\n");
    // }

    return sb.toString();
  }

  // Initializing application (do it once in login screen)
  public static String applicationInit(ServletContext application) {
    String message = init();
    application.setAttribute("projectName", projectName);
    return message;
  }

  public static String setupProperties(String dbHost, String dbPort, String dbUser, String dbPass,
          String projectName, String indriHome) {
    StringBuilder sb;

    p.setProperty("db_prefix", "sepia_" + projectName + "_");
    p.setProperty("db.hostname", dbHost);
    p.setProperty("db.portnumber", dbPort);
    p.setProperty("db.username", dbUser);
    p.setProperty("db.password", dbPass);
    p.setProperty("projectName", projectName);
    p.setProperty("indriHome", indriHome);
    p.setProperty("db_prefix", "sepia_" + projectName + "_");

    String version = readBundledConfig().getProperty("version", "");
    p.setProperty("version", version);

    storePropertyValues(p);

    try {
      FileOutputStream fos = new FileOutputStream(sepiaProperties.getAbsoluteFile());
      p.store(fos, "SEPIA Properties");
      sb = new StringBuilder();
      sb.append("Above configuration has been saved to: " + sepiaProperties.getAbsolutePath());
      sb.append("<a href=\"../index.jsp\" target=\"_blank\"></a>");
    } catch (IOException e) {
      sb = new StringBuilder();
      String error = "Failed to store the properties file to " + sepiaProperties.getAbsolutePath()
              + "\n" + ExceptionUtil.exceptionToString(e);
      logger.error(error);
      sb.append(error);
    }
    // call init(application) subsequently
    return sb.toString();
  }

  private static Properties getPropertiesFromHome(String fileName) {
    Properties p;
    try {
      // System.getenv() is deprecated?? Is it ok to use after jdk 1.5?
      sepiaHome = new File(System.getenv(SEPIA_HOME));
      sepiaProperties = new File(sepiaHome, fileName);

      InputStream is = new FileInputStream(sepiaProperties.getAbsolutePath());
      p = new Properties();
      p.load(is);
    } catch (Exception e) {
      p = null;
      if (sepiaHome == null) {
        logger.error("System Environmental Variable \"SEPIA_HOME\" is null.");
      } else if (!sepiaProperties.exists()) {
        logger.info("Properties file not found at "
                + sepiaProperties.getAbsolutePath()
                + ".\nYou need to set up SEPIA and put the properties file there with an accessible permission.");
      } else {
        logger.error(ExceptionUtil.exceptionToString(e));
      }
    }
    return p;
  }

  public static boolean initializedAlready() {
    File propFile = new File(System.getenv(SEPIA_HOME), SEPIA_PROPERTIES);
    if (!propFile.exists())
      return false;
    try {
      p = getPropertiesFromHome(SEPIA_PROPERTIES);
      String dbHost = p.getProperty("db.hostname");
      if (dbHost == null || dbHost.length() == 0) {
        return false;
      }
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  // new InputStreamReader( is, "utf8" ); is java6 specific
  public static String readResource(String fileName) {
    try {
      return IOUtil.readResource(fileName);
    } catch (IOException e) {
      e.printStackTrace();
      return null;
    }
  }

  public static Properties readBundledConfig() {
    Properties p = new Properties();
    try {
      p.load(Thread.currentThread().getContextClassLoader()
              .getResourceAsStream("config/config.properties"));
    } catch (Exception e) {
      e.printStackTrace();
    }
    return p;
  }

}
